<!DOCTYPE html>
<html lang="zh">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>封装</title>
    <script>
        /* 
        面向对象的三大特征

            1.封装-------(提供了安全性)
                对象就是一个用来存储不同属性的容器。
                对象不仅负责存储属性，还要负责数据的安全。
                直接添加到对象中的属性，并不安全，因为它们可以被任意修改。
                如何确保数据安全？
                    私有化数据
                        1.将我们需要保护的数据设为私有，只能在类的内部使用。

                        2.提供setter和getter方法来开放对数据的操作。

                            属性设置私有，通过getter,setter方法操作带来的好处
                                1.可以控制属性的读写权限。
                                2.可以在方法中对属性值进行验证。

                封装用来保证数据的安全性
                    实现封装的方式
                        1.属性私有化（就是加#号，而且这里一定要先声明私有化的属性）
                        2.通过getter和setter方法来操作属性

                            get 属性名(){
                                renturn this.#属性
                            }

                            set 属性名(参数){
                                this.#属性=参数
                            }

            2.多态-------(提供了灵活性)

            3.继承(extends)-------(提供了可扩展性)

                我们可以通过extends关键字来完成继承操作
                当一个类继承另一个类时，就相当于将一个类中的代码复制到当前类中（简单理解）
                继承发生时，被继承的类称为父类（超类），继承的称为子类
                通过继承可以减少重复的代码，并且可以在不修改一个类的前提下对齐进行拓展。            

        */
        class Person {

            //私有属性一定要先声明再使用，不一定要赋值，但一定要声明
            
            #address  //   实例属性添加 #开头，就会变私有属性,私有属性只能在类的内部访问
            #name
            #age
            #fn1

            constructor(a, b, c, d) {
                this.#name = a;
                this.#age = b;
                this.#fn1 = c;
                this.#address = d
            }

            fn2() {
                console.log(this.#name, this.#address)
            }
            
            //get方法用来读取属性
            getName() {
                return this.#name
            } 

            //set方法用来设置属性
            setAge(e){

                if(isNaN(e)){
                    console.log('您的输入存在非法问题')
                }

                else if(e>=0){
                this.#age=e
                }

                else if(e<0){
                    console.log('年龄输入必须为非负数')
                }
            }
            get address(){
                console.log('get执行了')
                return this.#address
            }
            set address(d){
                this.#address=d
            }

        }

        const p1 = new Person('孙悟空', 18, () => { console.log(this) }, '花果山')
        console.log(p1)
        //    console.log(p1.#address)      //报错
        // p1.#fn1()       // 私有属性不能在类的外部访问了
        p1.fn2()
        p1.getName()
        p1.setAge(12)
        console.log(p1)
        console.log(p1.address)
        console.log(p1.address='花果山水帘洞')


/* ==============================重新写个新的============================================================= */

        class Cat{

            #cat_name
            #cat_age
            #cat_address
            #cat_gender

            constructor(a,b,c,d){
                this.#cat_name=a
                this.#cat_age=b
                this.#cat_address=c
                this.#cat_gender=d
            }

            //读取猫的地址
            get read_cat_address(){
                return this.#cat_address
            }
            // 修改年龄    
            set write_cat_age(e){
                this.#cat_age=e
                return this.#cat_age
            }

        }

        const cat1= new Cat(
            '朱丽叶',
            2,
            '江苏南京',
            '女'
        )

        const cat2= new Cat(
            '罗密欧',
            5,
            '甘肃天水',
            '男'
        )
        
        console.log(cat1,cat2)
        console.log(cat1.read_cat_address)      //  控制台输出猫的地址
        console.log(cat2.write_cat_age=28)    
        console.log(cat2)
    </script>
</head>

<body>

</body>

</html>